bitkeeper revision 1.1718.1.5 (42b59f7dHnuJ9AFj24zaneKCDkFTCg)
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sun, 19 Jun 2005 16:38:21 +0000 (16:38 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sun, 19 Jun 2005 16:38:21 +0000 (16:38 +0000)
This patch adds dual-core support to xen, and improves HT detection.
Adapted from linux 2.6.12.
Signed-off-by: Nguyen Anh Quynh <aquynh@gmail.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/cpu/amd.c
xen/arch/x86/cpu/common.c
xen/arch/x86/cpu/cpu.h
xen/arch/x86/cpu/intel.c
xen/arch/x86/dom0_ops.c
xen/arch/x86/setup.c
xen/arch/x86/smpboot.c
xen/common/dom0_ops.c
xen/include/asm-x86/processor.h
xen/include/asm-x86/smp.h
xen/include/xen/smp.h

index 1241e5092186ef8aba430b1d99c5bb31e10e3df5..4b49e17f37005baa64300c8374a21b9f76b001f9 100644 (file)
@@ -193,23 +193,30 @@ static void __init init_amd(struct cpuinfo_x86 *c)
        }
 
        display_cacheinfo(c);
-       detect_ht(c);
-
-#ifdef CONFIG_X86_HT
-       /* AMD dual core looks like HT but isn't really. Hide it from the
-          scheduler. This works around problems with the domain scheduler.
-          Also probably gives slightly better scheduling and disables
-          SMT nice which is harmful on dual core.
-          TBD tune the domain scheduler for dual core. */
-       if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
-               smp_num_siblings = 1;
-#endif
 
        if (cpuid_eax(0x80000000) >= 0x80000008) {
                c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
                if (c->x86_num_cores & (c->x86_num_cores - 1))
                        c->x86_num_cores = 1;
        }
+
+#ifdef CONFIG_X86_HT
+       /*
+        * On a AMD dual core setup the lower bits of the APIC id
+        * distingush the cores.  Assumes number of cores is a power
+        * of two.
+        */
+       if (c->x86_num_cores > 1) {
+               int cpu = smp_processor_id();
+               unsigned bits = 0;
+               while ((1 << bits) < c->x86_num_cores)
+                       bits++;
+               cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
+               phys_proc_id[cpu] >>= bits;
+               printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
+                      cpu, c->x86_num_cores, cpu_core_id[cpu]);
+       }
+#endif
 }
 
 static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
index fcb5c16ecb96fff1864df1b12ce63c318af84a44..49661af7d84fff8670d223da22352524e3dee0d5 100644 (file)
@@ -186,7 +186,7 @@ static inline int flag_is_changeable_p(unsigned long flag)
 
 
 /* Probe for the CPUID instruction */
-int __init have_cpuid_p(void)
+static int __init have_cpuid_p(void)
 {
        return flag_is_changeable_p(X86_EFLAGS_ID);
 }
@@ -194,7 +194,7 @@ int __init have_cpuid_p(void)
 /* Do minimum CPU detection early.
    Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
    The others are not touched to avoid unwanted side effects. */
-void __init early_cpu_detect(void)
+static void __init early_cpu_detect(void)
 {
        struct cpuinfo_x86 *c = &boot_cpu_data;
 
@@ -228,6 +228,10 @@ void __init early_cpu_detect(void)
        }
 
        early_intel_workaround(c);
+
+#ifdef CONFIG_X86_HT
+       phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+#endif
 }
 
 void __init generic_identify(struct cpuinfo_x86 * c)
@@ -416,25 +420,15 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
        mcheck_init(c);
 #endif
 }
-/*
- *     Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
- */
-void __init dodgy_tsc(void)
-{
-       if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
-           ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC   ))
-               cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data);
-}
 
 #ifdef CONFIG_X86_HT
 void __init detect_ht(struct cpuinfo_x86 *c)
 {
        u32     eax, ebx, ecx, edx;
-       int     index_lsb, index_msb, tmp;
+       int     index_msb, tmp;
        int     cpu = smp_processor_id();
 
-       if (!cpu_has(c, X86_FEATURE_HT))
+       if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
                return;
 
        cpuid(1, &eax, &ebx, &ecx, &edx);
@@ -443,7 +437,6 @@ void __init detect_ht(struct cpuinfo_x86 *c)
        if (smp_num_siblings == 1) {
                printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
        } else if (smp_num_siblings > 1 ) {
-               index_lsb = 0;
                index_msb = 31;
 
                if (smp_num_siblings > NR_CPUS) {
@@ -452,21 +445,34 @@ void __init detect_ht(struct cpuinfo_x86 *c)
                        return;
                }
                tmp = smp_num_siblings;
-               while ((tmp & 1) == 0) {
-                       tmp >>=1 ;
-                       index_lsb++;
-               }
-               tmp = smp_num_siblings;
                while ((tmp & 0x80000000 ) == 0) {
                        tmp <<=1 ;
                        index_msb--;
                }
-               if (index_lsb != index_msb )
+               if (smp_num_siblings & (smp_num_siblings - 1))
                        index_msb++;
                phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
 
                printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
                       phys_proc_id[cpu]);
+
+               smp_num_siblings = smp_num_siblings / c->x86_num_cores;
+
+               tmp = smp_num_siblings;
+               index_msb = 31;
+               while ((tmp & 0x80000000) == 0) {
+                       tmp <<=1 ;
+                       index_msb--;
+               }
+
+               if (smp_num_siblings & (smp_num_siblings - 1))
+                       index_msb++;
+
+               cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
+
+               if (c->x86_num_cores > 1)
+                       printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+                              cpu_core_id[cpu]);
        }
 }
 #endif
@@ -511,7 +517,6 @@ extern int amd_init_cpu(void);
 extern int centaur_init_cpu(void);
 extern int transmeta_init_cpu(void);
 extern int rise_init_cpu(void);
-void early_cpu_detect(void);
 
 void __init early_cpu_init(void)
 {
index 9df38d993c396a21e986ada33bd9d5f0217725cc..5a1d4f163e84d6ff75a28aa91c6c65e3b53a717a 100644 (file)
@@ -25,7 +25,6 @@ extern int get_model_name(struct cpuinfo_x86 *c);
 extern void display_cacheinfo(struct cpuinfo_x86 *c);
 
 extern void generic_identify(struct cpuinfo_x86 * c);
-extern int have_cpuid_p(void);
 
 extern void early_intel_workaround(struct cpuinfo_x86 *c);
 
index 861723719b178c1403340cb5b06497b1f9369ef8..ef713eb95edd7c244151971dbf89c270d26be91b 100644 (file)
@@ -74,6 +74,27 @@ static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c)
 }
 
 
+/*
+ * find out the number of processor cores on the die
+ */
+static int __init num_cpu_cores(struct cpuinfo_x86 *c)
+{
+       unsigned int eax;
+
+       if (c->cpuid_level < 4)
+               return 1;
+
+       __asm__("cpuid"
+               : "=a" (eax)
+               : "0" (4), "c" (0)
+               : "bx", "dx");
+
+       if (eax & 0x1f)
+               return ((eax >> 26) + 1);
+       else
+               return 1;
+}
+
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
        unsigned int l2 = 0;
@@ -136,6 +157,8 @@ static void __init init_intel(struct cpuinfo_x86 *c)
        if ( p )
                strcpy(c->x86_model_id, p);
        
+       c->x86_num_cores = num_cpu_cores(c);
+
        detect_ht(c);
 
        /* Work around errata */
index e8979417ecb57cbece16e0cd4ebb34fd5b303c2f..2a269f11b6e7d7b36f4f597109d46253d1549e38 100644 (file)
@@ -179,8 +179,8 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
     {
         dom0_physinfo_t *pi = &op->u.physinfo;
 
-        pi->ht_per_core = ht_per_core;
-        pi->cores       = num_online_cpus() / ht_per_core;
+        pi->ht_per_core = smp_num_siblings;
+        pi->cores       = boot_cpu_data.x86_num_cores;
         pi->total_pages = max_page;
         pi->free_pages  = avail_domheap_pages();
         pi->cpu_khz     = cpu_khz;
index 0903967796be1cedddefd93f47e86a5eb12a0109..b0ebecfcee3aab4f44dc67c695a9cc098a05acde 100644 (file)
@@ -66,7 +66,6 @@ boolean_param("noapic", skip_ioapic_setup);
 
 int early_boot = 1;
 
-int ht_per_core = 1;
 cpumask_t cpu_present_map;
 
 /* Limits of Xen heap, used to initialise the allocator. */
index 80fe8122a46785a6c557c03ce7dd71467ab8990c..c9e1ac9151e47d3484e76b2cfa99fcff1c3644e3 100644 (file)
@@ -62,6 +62,8 @@ static int __initdata smp_b_stepping;
 int smp_num_siblings = 1;
 int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
 EXPORT_SYMBOL(phys_proc_id);
+int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
+EXPORT_SYMBOL(cpu_core_id);
 
 /* bitmap of online cpus */
 cpumask_t cpu_online_map;
@@ -923,6 +925,8 @@ static int boot_cpu_logical_apicid;
 void *xquad_portio;
 
 cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_core_map);
 
 static void __init smp_boot_cpus(unsigned int max_cpus)
 {
@@ -947,6 +951,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
        cpus_clear(cpu_sibling_map[0]);
        cpu_set(0, cpu_sibling_map[0]);
 
+       cpus_clear(cpu_core_map[0]);
+       cpu_set(0, cpu_core_map[0]);
+
        /*
         * If we couldn't find an SMP configuration at boot time,
         * get out of here now!
@@ -959,6 +966,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
                        printk(KERN_NOTICE "Local APIC not detected."
                                           " Using dummy APIC emulation.\n");
                map_cpu_to_logical_apicid();
+               cpu_set(0, cpu_sibling_map[0]);
+               cpu_set(0, cpu_core_map[0]);
                return;
        }
 
@@ -1079,10 +1088,13 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
         * construct cpu_sibling_map[], so that we can tell sibling CPUs
         * efficiently.
         */
-       for (cpu = 0; cpu < NR_CPUS; cpu++)
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
                cpus_clear(cpu_sibling_map[cpu]);
+               cpus_clear(cpu_core_map[cpu]);
+       }
 
        for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               struct cpuinfo_x86 *c = cpu_data + cpu;
                int siblings = 0;
                int i;
                if (!cpu_isset(cpu, cpu_callout_map))
@@ -1092,7 +1104,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
                        for (i = 0; i < NR_CPUS; i++) {
                                if (!cpu_isset(i, cpu_callout_map))
                                        continue;
-                               if (phys_proc_id[cpu] == phys_proc_id[i]) {
+                               if (cpu_core_id[cpu] == cpu_core_id[i]) {
                                        siblings++;
                                        cpu_set(i, cpu_sibling_map[cpu]);
                                }
@@ -1102,8 +1114,22 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
                        cpu_set(cpu, cpu_sibling_map[cpu]);
                }
 
-               if (siblings != smp_num_siblings)
+               if (siblings != smp_num_siblings) {
                        printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
+                       smp_num_siblings = siblings;
+               }
+
+               if (c->x86_num_cores > 1) {
+                       for (i = 0; i < NR_CPUS; i++) {
+                               if (!cpu_isset(i, cpu_callout_map))
+                                       continue;
+                               if (phys_proc_id[cpu] == phys_proc_id[i]) {
+                                       cpu_set(i, cpu_core_map[cpu]);
+                               }
+                       }
+               } else {
+                       cpu_core_map[cpu] = cpu_sibling_map[cpu];
+               }
        }
 
        if (nmi_watchdog == NMI_LOCAL_APIC)
index 216af3854ad43b69fdec1938b4e045750a55b4e2..8b3dd1edbc2ac56ceb7e1c53dd378032e80a588e 100644 (file)
@@ -184,8 +184,8 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
          * domains will all share the second HT of each CPU. Since dom0 is on 
             * CPU 0, we favour high numbered CPUs in the event of a tie.
          */
-        pro = ht_per_core - 1;
-        for ( i = pro; i < num_online_cpus(); i += ht_per_core )
+        pro = smp_num_siblings - 1;
+        for ( i = pro; i < num_online_cpus(); i += smp_num_siblings )
             if ( cnt[i] <= cnt[pro] )
                 pro = i;
 
index bec90dbab0770e040ae6629ab5bccf7f63573a3e..82b8cbce62777c38ab7adfbca489b8dddfb63410 100644 (file)
@@ -181,6 +181,7 @@ extern struct cpuinfo_x86 cpu_data[];
 #endif
 
 extern int phys_proc_id[NR_CPUS];
+extern int cpu_core_id[NR_CPUS];
 
 extern void identify_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
index c70f4d90fcc329ba6659459abde02011c102a83c..552b699bc44d80f8f1bf1fa5aa1d16e262ad4b48 100644 (file)
@@ -8,6 +8,7 @@
 #include <xen/config.h>
 #include <xen/kernel.h>
 #include <xen/cpumask.h>
+#include <asm/current.h>
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -34,6 +35,7 @@ extern void smp_alloc_memory(void);
 extern int pic_mode;
 extern int smp_num_siblings;
 extern cpumask_t cpu_sibling_map[];
+extern cpumask_t cpu_core_map[];
 
 extern void smp_flush_tlb(void);
 extern void smp_invalidate_rcv(void);          /* Process an NMI */
index 20042115890151393c055f40d9493683bf593067..57f7580adeaac867f7d53504b2cef5e21998f272 100644 (file)
@@ -58,8 +58,6 @@ static inline int on_each_cpu(void (*func) (void *info), void *info,
     return ret;
 }
 
-extern int ht_per_core;
-
 extern volatile unsigned long smp_msg_data;
 extern volatile int smp_src_cpu;
 extern volatile int smp_msg_id;